<?php

namespace App\Traits;


use App\Model\Test;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;

trait SplitTableTrait
{
    //是否分表，默认false，即不分表
    protected $isSplitTable = true;

    //原表
    public $originTable;

    //表
    public $endTable;

    /**
     * 后缀参数
     * @var string
     */
    protected $suffix = null;

    /**
     * 年月参数：202104
     * @var string
     */
    public $ym;

    public function init(array $attributes = [], $suffix = null)
    {
        //默认原表
        $this->originTable = $this->table;
        //默认最终表
        $this->endTable = $this->table;

        $this->ym = Carbon::now()->format('Ym');

        //isSplitTable参数为true时进行分表，否则不分表
        if ($this->isSplitTable) {
            //初始化后缀，未传则默认年月分表
            $this->suffix = $suffix ?: $this->ym;
        }
        //初始化分表表名并创建
        $this->setSuffix();
    }
    public function setTable($table){
        $this->table=$table;
    }
    /**
     * 设置表后缀, 如果设置分表后缀，可在service层调用生成自定义后缀表名，
     * 但每次操作表之前都需要调用该方法以保证数据表的准确性
     * @param $suffix
     */
    public function setSuffix($suffix = null)
    {

        //isSplitTable参数为true时进行分表，否则不分表
        if ($this->isSplitTable) {
            //初始化后缀，未传则默认年月分表
            $this->suffix = $suffix ?: $this->ym;
        }
        if ($this->suffix !== null) {
            //$this->endTable = $this->getTable() . '_' . $suffix;
            $this->endTable = $this->originTable . '_' . $this->suffix;
            //最终表替换模型中声明的表作为分表使用的表
            $this->table = $this->endTable;
        }

        //调用时，创建分表，格式为 table_{$suffix}
        //未传自定义后缀情况下,，默认按年月分表格式为：b_log_202101
        //无论使用时是否自定义分表名，都会创建默认的分表，除非关闭该调用
        $this->createTable();
    }

    /**
     * 提供一个静态方法设置表后缀
     * @param string $suffix
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public static function suffix($suffix = null)
    {

        $instance = new static;
        $instance->setSuffix($suffix);
        return $instance->newQuery();
    }
    /**
     * 提供一个静态方法设置表后缀
     * @param string $table
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public static function table($table = null)
    {
        $instance = new static;
        $instance->table=$table;
        return $instance->newQuery();
    }
    /**
     * 创建新的"table_{$suffix}"的模型实例并返回
     * @param array $attributes
     * @param bool $exists
     * @return object $model
     */
    // 创建新的"chapters_{$suffix}"的模型实例并返回
    public function newInstance($attributes = [], $exists = false)
    {
        $model = parent::newInstance($attributes, $exists);
        $model->setSuffix($this->suffix);

        return $model;
    }

    /**
     * 创建分表，没有则创建，有则不处理
     */
    protected function createTable()
    {
        info("createTable===============", [Schema::hasTable($this->endTable)]);
        //初始化分表,，按年月分表格式为：b_log_202101
        if (!Schema::hasTable($this->endTable)) {
            info("创建表==========", [$this->endTable]);
            DB::update("create table {$this->endTable} like {$this->originTable}");
        }
    }

    /**
     * 排序字段
     * @var
     */
    protected $orderByField = null;

    /**
     * 排序类型，asc：正序，desc：倒序，默认倒序
     * @var
     */
    protected $orderBy = 'desc';

    /**
     * 执行union all对分表的最终扥分页查询
     * @param $queries
     * @return array
     */
    public function dealListByUnionAllQuery($where=[],$with=[],$limit= 10)
    {

        try{
            $database=env('DB_DATABASE', 'forge');
            $table_name=$this->originTable;
            $table_where=[['table_schema','=',$database],['table_type','=','BASE TABLE'],['table_name','like',$table_name."_20%"]];
            $tables=DB::table("information_schema.tables")->select('TABLE_NAME')->where($table_where)->get();
            $queries = collect();
            $where=[['title','like','%测试%']];
            foreach($tables as $schema){
                $table=$schema->TABLE_NAME;
                $arr=explode("_",$table);
                $suffix=$arr[count($arr)-1];
                $queries->push(
                    self::suffix($suffix)
                );
            }
            $unionQuery = $queries->shift();
            // 循环剩下的表添加union
            $queries->each(function ($item, $key) use ($unionQuery) {
                $unionQuery->unionAll($item);
            });
            if($where){
                $unionQuery->where($where);
            }
            if($with){
                $unionQuery->with($with);
            }
            $lists = $unionQuery->get();
            //处理分页数据
            return $lists;
        }catch (\Throwable $E){
            dd($E);
        }
    }
    /**
     * 执行union all对分表的最终扥分页查询
     * @param $queries
     * @return array
     */
    public function UnionAllQuery($where=[],$limit= 5)
    {

        try{
            $database=env('DB_DATABASE', 'forge');
            $table_name=$this->originTable;
            $table_where=[['table_schema','=',$database],['table_type','=','BASE TABLE'],['table_name','like',$table_name."_20%"]];
            $tables=DB::table("information_schema.tables")->select('TABLE_NAME')->where($table_where)->get();
            $queries = collect();
            $where=[['title','like','%测试%']];
            foreach($tables as $schema){
                $table=$schema->TABLE_NAME;
                $queries->push(
                    DB::table($table)->where($where)
                );
            }
            $unionQuery = $queries->shift();
            // 循环剩下的表添加union
            $queries->each(function ($item, $key) use ($unionQuery) {
                $unionQuery->unionAll($item);
            });
            //设置临时表的名称，添加临时表，顺序不能反过来，否则用关联约束会找不到表
            $endQuery =
                DB::table(DB::raw("({$unionQuery->toSql()}) as union_" . $this->originTable))
                    //合并查询条件
                    ->mergeBindings($unionQuery);
            if ($this->orderByField) {
                $endQuery->orderBy($this->orderByField, $this->orderBy);
            }
            $lists = $endQuery
                //分页
                ->paginate($limit)
                ->toArray();
            return $lists;
        }catch (\Throwable $E){
            dd($E);
        }
    }
}
